Repository navigation
feat(spec): an Oracle RAW(16) uuid column backs a lookup, master_detail or user field exactly again - #31786
Conversation
…ctly again The SQL driver now binds a RAW(16) comparand, written value and by-id key through HEXTORAW, so the oracle uuid demotion narrows to the text pairing alone: lookup, master_detail and user answer exact; text stays lossy because its pattern operators match the column's hex text. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jULf9M1RFFq4dq9ioH
…-h15c0w Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jULf9M1RFFq4dq9ioH
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 171 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9ae6fc895624857d4ccc8079d9e892adb8b25319 && git checkout 9ae6fc895624857d4ccc8079d9e892adb8b25319
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e253f3ab09717234fedae8e4d7a193cd1a12b0da e090be93463b7273a813ee3cdfcb2c7863d6619b && git checkout -B drift-repro e253f3ab09717234fedae8e4d7a193cd1a12b0da && git merge --no-ff e090be93463b7273a813ee3cdfcb2c7863d6619b
node scripts/docs-audit/affected-docs.mjs --json e253f3ab09717234fedae8e4d7a193cd1a12b0da |
|
domain:spec#2 · zhuangjianguo · session_01QsR2jUe9c6YdtNkrzUnMUd Contract-review-claim: session_01QsR2jUe9c6YdtNkrzUnMUd · head e090be9 · 2026-11-09T04:22Z The seat runs the CONTRACT_REVIEW_TIER review on an isolated sub-agent (director seat off duty; maintainer rule 2026-11-08 「有 fable 车道就可以契约复审啊」). CI on this head: 57 success, 10 skipped, 0 failed. |
|
domain:spec#2 · zhuangjianguo · session_01QsR2jUe9c6YdtNkrzUnMUd Contract reviewServed-tier: Inputs read: card #31592 (body, triage 6724356074, unblock 6730608741, claim 6731116574, dev report 6731804928), PR #31786 (body, 5-file list, net diff against ① Derived judgments
② Semver level
Clause-②: ③ Boundary flagsDev report 6731804928:
No ruling on the card is contradicted. Triage's lane and grade ( ④ Design judgment
Implementing files in the diff apart from Findings: F1 nit, F2 nit, F3 nit. No must-fix, no should-fix: nits alone end the round. Rendered by the seat's isolated child session Implemented-by: VERDICT: PASS Seat adoption note: read before adopting. Spot-checked the pattern-operator premise ( |
|
domain:spec#2 · zhuangjianguo · session_01QsR2jUe9c6YdtNkrzUnMUd 维护者速读
席位核对 · ACCEPT · 2026-11-09T04:31Z · head
|
Requested by Steedos · project thread
Fixes #31592
Clause-②: yes (widening)
Metadata-protocol: semantic
Skills-docs: none —
git grep -i 'raw(16)|HEXTORAW|isCompatible|type-compat|lossy' -- skills .claude/skillshas 0 hits; no skill states this matrix.维护者速读
RAW(16)的 uuid 列,配lookup/master_detail/user字段时,类型兼容矩阵从「有损」改回「精确」;配text字段仍判有损。只改packages/spec的判定函数,外加文档、ADR-0015 §4.6 和 changeset。HEXTORAW(?)绑定这类列的比较值、写入值和按 id 定位的键,所以SYS_GUID()主键上的 lookup 现在能按读出来的 uuid 筛选、写入、改删。矩阵还标着有损,校验就会对每个这样的 lookup 报type_mismatch警告。text不放宽,因为$contains这类模式运算符没走HEXTORAW,Oracle 会拿列的大写无横线十六进制去匹配,用读出来的 uuid 片段搜不到行,也不报错。回滚即 revert 本 PR。packages/spec/src/data/type-compat.ts(DIALECT_LOSSY_RULES的 oracle 行和isCompatible第一行判断)、docs/adr/0015-external-datasource-federation.md§4.6、content/docs/data-modeling/external-datasources.mdx的 Oracle 一节。pnpm --filter @objectstack/spec exec vitest run src/data/type-compat.test.ts,预期 42 个测试全绿;其中 RAW(16) 一条断言 lookup / master_detail / user 为true、text 为'lossy'。docs/adr/**,Tier H),之后由席位落地。What changes
isCompatible, oracleRAW(16).DialectLossyRule.demoteExactwas a flag that demoted every exact pairing of the canonical type. It is now the list of exact pairings it demotes. The oracleuuidrow namestextonly. SoisCompatible('RAW(16)', 'lookup' | 'master_detail' | 'user', 'oracle')answerstrue(was'lossy'), and'text'still answers'lossy'. The rule type is module-private, so no export changes.demoteExactis still used by oracle fortext, so it is not dead.mssql/textaddLossyis unchanged.DIALECT_LOSSY_RULESdocblock no longer says "Binding throughHEXTORAWis driver-sql (oracle): bind uuid text to RAW(16) through HEXTORAW, so a lookup over a SYS_GUID key filters and writes by its uuid string, and type-compat can lift the pairing from lossy to compatible #31390". It now says what the driver binds and whytextis still demoted. TheRAW(n)paragraph aboveoracleParameterisedTypematches.external-datasources.mdx, theRAW(16)table row says the column is filtered and written by its uuid string. It says a reference field over it is exact and atextfield is lossy. The old "not supported" bullet now describes the bind, the accepted uuid forms, and the refusals the driver-sql (oracle): bind uuid text to RAW(16) through HEXTORAW, so a lookup over a SYS_GUID key filters and writes by its uuid string, and type-compat can lift the pairing from lossy to compatible #31390 changeset names (INVALID_FILTER,VALIDATION_ERROR, a create with no id on aRAW(16)key). A new bullet says what the pattern operators match.RAW(16)sentence and theDIALECT_LOSSY_RULESsentence (both in §4.6) are corrected. TheAmended byline gains a dated#31592 (2026-11-09)entry..changeset/31592-oracle-raw16-reference-exact.md,@objectstack/specminor, carrying both declaration lines.Why
Card task (Ruling-ref: ADR-0015 §4.6): "drop the oracle /
uuiddemoteExactrule (or narrow it) soRAW(16)→lookup/master_detailanswers compatible again". Also: "the pairing must not be declared before the runtime honours it". Triage 6724356074: "Moving a type-compat pair fromlossyto compatible widens an acceptance set, which is a metadata-protocol change under #31424 rule 2."Which paths #31390 binds, read on
main(836d408f). I checked these inpackages/drivers/driver-sql/src/and the #31390 tests insql-driver-oracle-dialect.test.ts.=,$eq,$ne,$in,$nin, the range operators) bind throughHEXTORAW. SeecoerceFilterValueandassertOracleUuidComparand, in both the operator-object and bare-equality branches.{ id: { $in: [...] } }(packages/objectql/src/engine-summaries-and-expansion.tsL593), which is the comparand path.So
lookup,master_detailanduserare honoured, and the narrowing lifts exactly those three.What is still not honoured: pattern operators. The pin
control: a pattern operator on the RAW(16) column compiles its text pattern as before, unjudgedshows it:$contains: 'abc'compiles to"ACCT_REF" LIKE ? ESCAPE ?with'%abc%', with noHEXTORAWand no conversion. Oracle converts aRAWto character data as its hex digits (upper case, no hyphens). A fragment of the string a read returns matches no row if it holds a hyphen, and under a case-sensitive operator ($contains,$startsWith) a lower-case fragment matches none at all. No error is raised. For atextfield those operators are its own (list search is an$orof$icontains,packages/objectql/src/search-filter.ts), sotextstays'lossy'and a draft keeps its// REVIEW:marker. A reference field is filtered by id equality or membership, which is bound.Consumers of
isCompatibleonmain(packages/services/service-datasource/src/external-datasource-service.ts):// REVIEW:: no change. It judges the suggested type, which forRAW(16)istext, and that stays'lossy'.!== truelookup gate: no change for oracle. It runs only for ODatanavigationProperties(navigationCandidates), and a SQL table has none.validateObject: alookup/master_detail/userfield over an oracleRAW(16)column no longer gets thetype_mismatchwarning.textkeeps it.'lossy'answer: none.git grep -n -i "RAW(16)\|demoteExact"inpackages/services/service-datasourcefinds 0. The suite is green unchanged (see Tests).driver-sql/src/builtin-column-collision.ts, which is not about oracle.Tests
packages/spec/src/data/type-compat.test.ts, theRAW(16)case:lookup,master_detail,usernow pintrue, andtextpins'lossy'. It also pins that the demotion promotes nothing (numberstaysfalse). The suggested type is stilltext. Postgresuuid/lookupis stilltrue, and otherRAWwidths are stillbinary.scripts/ablation-replace.mjs, mutation proven on disk, restored to HEAD):isCompatibleback to the flag reading (rule?.demoteExact ? 'lossy' : true). Result: red,lookup: expected 'lossy' to be true, 1 failed / 41 passed.demoteExact: []. Result: red,expected true to be 'lossy'(thetextleg), 1 failed / 41 passed.src(the spec suite imports./type-compatdirectly), so nodistpreflight applies.Acceptance notes
OS_TEST_ORACLE_URLhere. TheHEXTORAWbind is driver-sql (oracle): bind uuid text to RAW(16) through HEXTORAW, so a lookup over a SYS_GUID key filters and writes by its uuid string, and type-compat can lift the pairing from lossy to compatible #31390's, and its live conformance cell is also unmeasured in CI. The claim that pattern operators match the hex text rests on Oracle's documented implicitRAWto character conversion and on the compiled-SQL pin above, not on a live run.RAW(16)sentence (L431-434), theDIALECT_LOSSY_RULESsentence in the same §4.6 that said oracle "demotes the exact pairings ofuuid" (which this change makes false), and theAmended byline. Nodriver-sqlchange.uuidrow keepsuserexact on every dialect. A platform user id is a 32-character better-auth string or a 16-character nanoid, never a uuid. So a uuid column (postgresuuid, mssqluniqueidentifier, and now oracleRAW(16)too) refuses a real platform user id on write. That is the base row's judgement, the same on every dialect, and this card does not reopen it. Noted, not filed.createwithout an id on an object keyed by aRAW(16)column isVALIDATION_ERROR(the minted nanoid is not a uuid), per driver-sql (oracle): bind uuid text to RAW(16) through HEXTORAW, so a lookup over a SYS_GUID key filters and writes by its uuid string, and type-compat can lift the pairing from lossy to compatible #31390. The docs bullet now says so.Verification
Head
e090be93(0a902b02merged withorigin/mainatf6474306).mainmoved nothing underpackages/specorpackages/services/service-datasourcein that merge.Suites
pnpm --filter @objectstack/spec build: VERDICT command-exit 0, rebuilt after the merge.pnpm --filter @objectstack/spec check:generated: exit 0, "All 14 generated artifacts are up to date".pnpm --filter @objectstack/spec test: 824 files passed, 26081 tests passed, 1 todo, VERDICT command-exit 0.pnpm --filter @objectstack/spec typecheck: VERDICT command-exit 0.pnpm --filter @objectstack/service-datasource test(consumer, after its^...closure build): 74 files, 1299 tests passed, VERDICT command-exit 0.distreading:isCompatible('RAW(16)', X, 'oracle')gives textlossy, lookuptrue, master_detailtrue, usertrue, numberfalse. Postgresuuid/ lookup istrue, mssqlnvarchar(max)/ json islossy.spectest:repowas not run locally. It is CI's (Test Core).Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives 108 families. 107 exited 0.pnpm check:dual-build-cjs-loadsexited 3 (PREREQUISITE NOT MET: it needs a full workspace build). That is NOT MEASURED locally, and CI runs it.check:doc-formula-expressions,check:doc-security-posture,check:skill-examples). Each exited 0 after a lockedturbo run buildof formula, lint and client-react.main, the five gates whose scripts the merge moved were re-run, each exit 0:check:ci-filter-parity,check:cross-package-test-inputs,check:pm-governed-merges,check:engine-double-contract,check:adr-anchors.--ranreconciliation: 108 derived, 107 run, 1 NOT-MEASURED, 0 UNRUN.dispatch-gates --tier:docs/adr/**is Tier H. Changed lines: 94, under 3000.Human Minimum
packages/specholds no runtime logic.pnpm lintpasses. (No formatter ran.pnpm lintis CI's.)main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed. (check:generatedreports none stale.)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code